package com.sxyjhh.utils.util;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
 * Class description:对象拷贝通用工具类
 * @JDK Version:  1.8.0_40
 * @version       V1.0, 2017.04.07 at 11:14:15 CST
 * @Author        Shaok Lei
 */
public class BeanUtil {
    /**
     * Method description：拷贝对象属性到目标对象属性中，利用反射实现对象之间相同属性复制，包括继承的属性，不复制指定名称的属性值
     * Version:V1.0
     * Author:Shaok Lei
     * Date:2017.04.07 at 11:15:06 CST
     *
     * @param fromObj 源对象
     * @param toObj 目标对象
     * @param excludsArray  指定不要赋值的对象属性名
     *
     * @throws Exception
     */
    public static void copyExclude(Object fromObj, Object toObj, String[] excludsArray) throws Exception {
        List<String> excludesList = null;
        // 判断是否指定了不需要拷贝的属性字段
        if ((excludsArray != null) && (excludsArray.length > 0)) {
            excludesList = Arrays.asList(excludsArray);    // 构造列表对象
        }

        List<Method> toMethodList = new ArrayList<Method>();
        List<Method> fromMethodList = new ArrayList<Method>();

        // 获取目标对象的属性get、set方法列表
        Method[] toMethodSelf = toObj.getClass().getDeclaredMethods();
        Method[] toMethodSuper = toObj.getClass().getSuperclass().getDeclaredMethods();
        if (toMethodSelf != null){
            List<Method> tempList = Arrays.asList(toMethodSelf);
            toMethodList.addAll(tempList);
        }
        if(toMethodSuper != null){
            List<Method> tempList = Arrays.asList(toMethodSuper);
            toMethodList.addAll(tempList);
        }

        // 获取源对象的属性get、set方法列表
        Method[] fromMethodSelf = fromObj.getClass().getDeclaredMethods();
        Method[] fromMethodSuper = fromObj.getClass().getSuperclass().getDeclaredMethods();
        if (fromMethodSelf != null){
            List<Method> tempList = Arrays.asList(fromMethodSelf);
            fromMethodList.addAll(tempList);
        }
        if (fromMethodSuper != null){
            List<Method> tempList = Arrays.asList(fromMethodSuper);
            fromMethodList.addAll(tempList);
        }

        Method   fromMethod = null;
        Method   toMethod = null;
        String   fromMethodName = null;
        String   toMethodName   = null;

        // 循环获取源对象的属性并拷贝
        for (int i = 0; i < fromMethodList.size(); i++) {
            fromMethod     = fromMethodList.get(i);
            fromMethodName = fromMethod.getName();

            // 不是get方法的话直接过滤掉
            if (!fromMethodName.contains("get")) {
                continue;
            }

            // 排除列表检测，指定名称的属性值直接过滤掉
            String propertyName = fromMethodName.substring(3, 4).toLowerCase() + fromMethodName.substring(4);
            if ((excludesList != null) && excludesList.contains(propertyName)) {
                continue;
            }
            // 判断在目标对象中是否存在同名属性对应的set方法
            toMethodName = "set" + fromMethodName.substring(3);
            toMethod     = findMethodByName(toMethodList, toMethodName);

            if (toMethod == null) {
                continue;
            }

            /*
             * 获取属性值并根据属性值判断属性是否为空，如果不为空则进行赋值操作
             */
            Object value = fromMethod.invoke(fromObj, new Object[0]);

            // 非集合类判空处理
            if (value == null) {
                continue;
            }

            // 集合类判空处理
            if (value instanceof Collection) {
                Collection<?> newValue = (Collection<?>) value;

                if (newValue.size() <= 0) {
                    continue;
                }
            }

            // 通过反射调用set方法进行赋值操作
            Object[] valueObj = new Object[] { value };

            toMethod.invoke(toObj, valueObj);
        }
    }
    /**
     * Method description：从方法数组中获取指定名称的方法
     * Version:V1.0
     * Author:Shaok Lei
     * Date:2017.04.07 at 11:15:34 CST
     *
     * @param methods get、set方法集合
     * @param name 方法名称
     * @return
     */
    public static Method findMethodByName(List<Method> methods, String name) {
        for (int j = 0; j < methods.size(); j++) {
            if (methods.get(j).getName().equals(name)) {
                return methods.get(j);
            }
        }
        return null;
    }
}
